﻿/// <reference path="_namespace.js" />



// Animation.Raster

if ( typeof(Animation) == "undefined" ) Animation = function () {};

Animation.Raster = function (container,imgsrc) {
    if ( ! container ) return;
    this.initialized = false;       // canvas size is known or not
    this.startOnLoad = false;       // start commanded received
    this.started = false;           // start flag
    this.finished = false;          // all done flag
    this.linebuf = [];              // rect lines buffer
    this.trush = [];
    this.onComplete = null;         // call back function
    this.initialize(container,imgsrc);
    return this;
};

Animation.Raster.VERSION = "0.02";
Animation.Raster.prototype.waveSpeed = 0.5;
Animation.Raster.prototype.waveHeight = 0.5;
Animation.Raster.prototype.lineHeight = 6;
Animation.Raster.prototype.downSeconds = 1.0;
Animation.Raster.prototype.fadeSeconds = 4.0;
Animation.Raster.prototype.clip = true;
Animation.Raster.prototype.background = null;

Animation.Raster.prototype.initialize = function( container,imgsrc ) {
    if ( typeof container == "string" ) {
        container = document.getElementById(container);
    }
    if ( ! container ) return;

    this.outer = document.createElement( "div" );
    this.outer.style.position = "relative";

    this.canvas = document.createElement( "div" );
    this.canvas.style.position = "absolute";
    this.outer.appendChild( this.canvas );

    if ( imgsrc ) {
        container.appendChild( this.outer );
        this.original = document.createElement( "img" );    // source image
        this.original.src = imgsrc;
        this.original.style.visibility = "hidden";
        this.outer.appendChild( this.original );
        this.getImageSize( this.original );
    } else {
        container.parentNode.insertBefore( this.outer, container );
        this.original = container;                      // original
        this.original.style.visibility = "hidden";
        this.canvasWidth  = this.original.offsetWidth;
        this.canvasHeight = this.original.offsetHeight;
        this.initialized = true;                        //
    }
};

Animation.Raster.prototype.getImageSize = function( orig ) {
    var loadmess = this.message( "Now loading..." );
    var checksize = orig.cloneNode(true);      // image for checking
    checksize.style.position = "absolute";
    var __this = this;
    var ldfunc = function(e){
        if ( ! e && window.event ) e = window.event;    // IE
        __this.canvasWidth  = checksize.offsetWidth;
        __this.canvasHeight = checksize.offsetHeight;
        __this.initialized = true;
        checksize.parentNode.removeChild( checksize );
        loadmess.parentNode.removeChild( loadmess );
        if ( __this.startOnLoad ) {
            __this.beginAnimation();
        }
    };
    this.appendEvent( checksize, "load", ldfunc );  // onload image
    this.outer.appendChild( checksize );
};

Animation.Raster.prototype.clipCanvas = function() {
    if ( ! this.canvasWidth || ! this.canvasHeight ) return;
    this.canvas.style.width  = this.canvasWidth+"px";
    this.canvas.style.height = this.canvasHeight+"px";
    if ( this.clip ) {
        this.canvas.style.clip = "rect(0px,"+(this.canvasWidth)+"px,"+(this.canvasHeight)+"px,0px)";
    }
}

Animation.Raster.prototype.clickToFinish = function() {
    var __this = this;
    var clfunc = function(e){
        if ( ! e && window.event ) e = window.event;    // IE
        if ( ! __this.initialized ) return;                  // not loaded yet
        if ( ! __this.started ) return;                 // not started yet
        if ( __this.finished ) return;                      // already done
        __this.finish();
    };
    this.appendEvent( this.canvas, "click", clfunc );        // onclick canvas
}

Animation.Raster.prototype.message = function( mess ) {
    var tload = document.createTextNode( mess );
    elem = document.createElement( "span" );
    elem.appendChild( tload );
    elem.style.color = "#FFFFFF";
    elem.style.background = "#FF3333";
    elem.style.position = "absolute";
    elem.style.fontSize = "12px";
    elem.style.fontFamily = "Helvetica";
    elem.style.fontWeight = "bold";
    elem.style.width = "14em";
    elem.style.padding = "4px";
    if ( this.outer.firstChild ) {
        this.outer.insertBefore( elem, this.outer.firstChild );
    } else {
        this.outer.appendChild( elem );
    }
    return elem;
}

Animation.Raster.prototype.appendEvent = function( elem, type, func ) {
    if ( elem.addEventListener ) {
        return elem.addEventListener( type, func, false );
    } else if ( elem.attachEvent ) {
        return elem.attachEvent( "on"+type, func );
    }
};

Animation.Raster.SinCache = [];

Animation.Raster.prototype.get_sin_table = function(intrv) {
    if ( Animation.Raster.SinCache[intrv] ) return Animation.Raster.SinCache[intrv];
    var sintable = [];
    for( var i=0; i<intrv; i++ ) {
        sintable[i] = Math.sin(2.0 * Math.PI * i / intrv);
    }
    Animation.Raster.SinCache[intrv] = sintable;
    return sintable;
};

Animation.Raster.prototype.beginAnimation = function() {
    if ( this.background ) this.canvas.style.background = this.background;
    var sinsize = Math.floor( this.canvasHeight / this.lineHeight );
    this.sinTable = this.get_sin_table(sinsize);
    this.clipCanvas();
    this.clickToFinish();

    var lines = Math.floor(this.canvasHeight/this.lineHeight);
    for( var i=lines; i>=0; i-- ) {
        this.cloneLine(i,this.lineHeight)
    }

    this.timer = new Animation.Raster.Timer(this);                  // timer object
    this.timer.start();
};

Animation.Raster.prototype.scroll = function() {
    this.started = true;
    if ( this.initialized ) {
        this.beginAnimation();
    } else {
        this.startOnLoad = true;  // wait until image loaded
    }
};

Animation.Raster.prototype.cloneLine = function(top,lines) {
    if ( this.linebuf[top] ) return this.linebuf[top];
    var newline = this.original.cloneNode(true);
    newline.style.position = "absolute";
    newline.style.visibility = "hidden";
    newline.style.clip = "rect("+(top*lines)+"px,"+(this.canvasWidth)+"px,"+((top+1)*lines)+"px,0px)";
    this.canvas.appendChild( newline );
    this.linebuf[top] = newline;
    return newline;
};

Animation.Raster.prototype.loop = function(secs,count) {
    var lines = Math.floor(this.canvasHeight/this.lineHeight);
    secs *= 0.001;  // millisec to second

    var wavy = this.canvasHeight*this.waveHeight;
    var y = 0;
    var top = 0;
    if ( secs < this.downSeconds ) {
        var prog1 = secs/this.downSeconds;
        y = Math.floor(prog1*this.canvasHeight) - this.canvasHeight;
        y -= y % this.lineHeight;
        top = Math.floor( lines*(1.0-prog1) );
    } else if ( secs < this.downSeconds + this.fadeSeconds ) {
        var prog3 = (secs-this.downSeconds)/this.fadeSeconds;
        wavy *= (1.0-prog3);
    } else {
        this.finish();
        return false;
    }

    var wavecnt = Math.floor(secs*this.sinTable.length*this.waveSpeed);
    for( var i=top; i<=lines; i++ ) {
        var x = Math.floor( wavy * this.sinTable[(i-top+wavecnt)%this.sinTable.length] );
        this.linebuf[i].style.left = x+"px";
        this.linebuf[i].style.top = y+"px";
        this.linebuf[i].style.visibility = "visible";
    }
    return true;
};

Animation.Raster.prototype.finish = function() {
    if ( this.timer ) {
        if ( this.timer.is_running() ) this.timer.stop();
        this.timer = null;
    }
    if ( this.finished ) return;
    this.original.style.visibility = "visible";
    this.canvas.style.background = "";
    for( var i=0; i<this.linebuf.length; i++ ) {
        if ( ! this.linebuf[i] ) continue;
        if ( ! this.linebuf[i].parentNode ) continue;
        this.linebuf[i].parentNode.removeChild( this.linebuf[i] );
        this.linebuf[i] = null;
    }
    for( var i=0; i<this.trush.length; i++ ) {
        if ( ! this.trush[i] ) continue;
        if ( ! this.trush[i].parentNode ) continue;
        this.trush[i].parentNode.removeChild( this.trush[i] );
        this.trush[i] = null;
    }
    this.finished = true;
    if ( this.onComplete ) this.onComplete( this.original );
};

//  Animation.Raster.Timer class

Animation.Raster.Timer = function (target) {
    this.target = target;
    this.started = false;
    this.stoped = false;
    this.count = 0;
    var __this = this;
    this.next = function(){
        if ( __this.stoped ) return;
        var now_time = (new Date()).getTime();
        if ( ! __this.begin_time ) __this.begin_time = now_time;
        var spent_time = now_time-__this.begin_time;
        var flag = __this.target.loop(spent_time,__this.count++);
        if ( flag ) {
            setTimeout( __this.next, 1 );
        } else {
            __this.stop();
        }
    };
    return this;
};
Animation.Raster.Timer.prototype.start = function () {
    this.started = true;
    this.stoped = false;
    this.next();
};
Animation.Raster.Timer.prototype.stop = function () {
    this.stoped = true;
};
Animation.Raster.Timer.prototype.is_running = function () {
    return ( this.started && ! this.stoped );
};

/*
// ========================================================================

=head1 NAME

Animation.Raster -- Virtual Raster Scrolling Animation

=head1 SYNOPSIS

    var ras = new Animation.Raster( id_or_elem, image_url );
    ras.lineHeight  = 6;                    // scroll line's height
    ras.clip        = true;                 // clip animation area (default: true)
    ras.background  = "#000000";            // animation area's background
    ras.downSeconds = 1.0;                  // falling down animation
    ras.fadeSeconds = 4.0;                  // fading wave animation
    ras.waveSpeed   = 0.5;                  // wave's speed
    ras.onComplete  = function () { ... };  // callback function
    ras.scroll();

=head1 DESCRIPTION

This library provides a animation effect of virtual raster scrolling 
for images and block elements.

=head1 METHODS

=head2 ras = new Animation.Raster( id_or_elem, image_url );

This constructor method returns a new Animation.Raster object.
The first argument is the animation's container element or its id string.
The second argument is the target image's URL for raster scrolling.
If URL is not defined, container element itself is animated.

=head2 ras.scroll();

This method starts a animation effect.

=head2 ras.finish();

This method forces to stop a animation effect if it's running.

=head1 AUTHOR

Yusuke Kawasaki http://www.kawa.net/

=head1 COPYRIGHT AND LICENSE

Copyright (c) 2005-2006 Yusuke Kawasaki. All rights reserved.
This program is free software; you can redistribute it and/or
modify it under the Artistic license. Or whatever license I choose,
which I will do instead of keeping this documentation like it is.

=cut
// ========================================================================
*/


// Create our own class that extends the Animation.Raster provided (as is).
ajax.lang.addNamespace("ajax.effects");

ajax.effects.Scroll = function(container,imgsrc)
{///<param name="container">id_or_elem</param>
 ///<param name="imgsrc">image_url or null (to animate existing container content)</param>
    ajax.effects.Scroll.superConstructor.call(this, container, imgsrc);
}
$extend("ajax.effects.Scroll", "Animation.Raster");
if ($getDesignMode())
    ajax.effects.Scroll.prototype = Animation.Raster.prototype;  
      
ajax.effects.Scroll.cast = function(obj)
{///<returns type="ajax.effects.Scroll"/>
    return obj;    
}
